package applicationFunction.socks.nwct;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.LinkedList;
import java.util.logging.Logger;

/**
 * 存储Socket
 */
public class SocketPoolServer {
    private static Logger logger = Logger.getLogger("applicationFunction.socks.nwct.SocketPoolServer");

    /**
     * 正在使用的socket
     */
    private LinkedList<Socket> usingSocket = new LinkedList<>();//因为有大量的删除操作且没有随机get，所以用LinkedList 数据结构

    /**
     * 可用的 关于这里面的socket， socket里面 java.net.Socket#setSoTimeout(int) 给出解释，当timeout设置为0的时候为无限超时，如果不行，在内网机上面设置超时时间，然后再一个线程 设置比超市时间少的 重置连接池。
     */
    private LinkedList<Socket> avaliableSocket = new LinkedList<>();

    private ServerSocket server;

    private boolean destroy = false;

    public void start() throws IOException {
        start(6666);
    }

    public void start(int port) throws IOException {
        server = new ServerSocket(port);
        Listener listener = new Listener();
        Monitor monitor = new Monitor();
        Thread listenerThread = new Thread(listener);
        Thread monitorThread = new Thread(monitor);
        listenerThread.start();
        monitorThread.start();
    }


    public void clearAvaliableSocketAndCloseSocket() throws IOException {
        if (avaliableSocket.size() > 0) {
            synchronized (avaliableSocket) {
                for (Socket s : avaliableSocket) {
                    s.close();
                    avaliableSocket.remove();
                }
            }
        }
    }

    /**
     * 讲avaliable 中的socket 移动到using 中
     *
     * @return
     */
    public Socket useSocket() {
        Socket result = null;
        boolean success = false;
        while(!success&& avaliableSocket.size()>0) {
            Socket temp = null;
            synchronized (avaliableSocket) {
                temp = avaliableSocket.pop();
            }
            if (temp != null&& !temp.isClosed()) {
                result = temp;
                success =true;
                synchronized (usingSocket) {
                    usingSocket.add(result);
                }
            }
        }

        return result;
    }

    /**
     * 清空usingSocket 当有再使用的sokcet时，等待3s 然后强制关闭
     *
     * @param enforce true 清空 usingSocket 时并强制关闭Socket
     */
    public void clearUsingSocketAndCloseSocket(boolean enforce) throws IOException {
        if (usingSocket.size() > 0) {
            synchronized (usingSocket) {
                for (Socket s : usingSocket) {
                    if (enforce) {
                        s.close();
                    }
                    if (s.isClosed()) {
                        usingSocket.remove();
                    }
                }
            }
        }
        else {
            return;
        }
        if (!enforce) {
            try {
                Thread.sleep(3000);
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (usingSocket.size() > 0) {
                synchronized (usingSocket) {
                    for (Socket s : usingSocket) {
                        s.close();
                        usingSocket.remove();
                    }
                }
            }
        }
    }

    /**
     * 关闭资源
     */
    public synchronized void destroy() {
        destroy = true;
        try {
            clearAvaliableSocketAndCloseSocket();
            clearUsingSocketAndCloseSocket(false);
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 监听线程，
     */
    class Listener implements Runnable {

        @Override
        public void run() {
            while (!destroy) {
                try {
                    Socket socket = server.accept();
                    synchronized (avaliableSocket) {
                        avaliableSocket.add(socket);
                        logger.info("avaliableSocket is start "+socket);
                    }
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 监控线程
     */
    class Monitor implements Runnable {

        /**
         * 删除已经使用过的 Socket
         */
        public void deleteUsedSocket() {
            synchronized (usingSocket) {
                int length = usingSocket.size();
                for (int i = length-1; i >0; i--) {
                    if (usingSocket.get(i).isClosed()) {
                        logger.info("usingSocket is close "+usingSocket.get(i));
                        usingSocket.remove(i);
                    }
                }
            }
        }

        @Override
        public void run() {
            while (!destroy) {
                deleteUsedSocket();
                try {
                    Thread.sleep(3000L);
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}
